home *** CD-ROM | disk | FTP | other *** search
/ Programmer Power Tools / Programmer Power Tools.iso / progjrn / pj_7_1.arc / WINH19FN.C < prev   
Text File  |  1988-10-23  |  15KB  |  532 lines

  1. /*
  2.  * Windows H-19 emulator
  3.  * 
  4.  * Written by William S. Hall
  5.  *          3665 Benton Street, #66
  6.  *          Santa Clara, CA 95051
  7.  *
  8.  * Emulator function support module - extracts
  9.  */
  10.  
  11. /* 
  12.  * If the terminal is off-line, then the keypad keys
  13.  * on an H-19 send the appropriate escape sequence
  14.  * back to the terminal.  We emulate this behavior here.
  15.  * This function is called from the main window procedure when
  16.  * a WM_KEYDOWN key is received.
  17.  */
  18. void NEAR H19LocalKeyDown(WORD keycode)
  19. {
  20.   /* 
  21.    * Since the child windows act as the H-19 screen and status line,
  22.    * we simply pass on the appropriate action to the active window.
  23.   */
  24.     switch (keycode) {
  25.     case VK_UP:
  26.         SendMessage(hWndActive,WH19_COMMAND,H19_MOVECURSORUP,1L);
  27.         break;
  28.     case VK_DOWN:
  29.         SendMessage(hWndActive,WH19_COMMAND,H19_MOVECURSORDOWN,1L);
  30.         break;
  31.     case VK_RIGHT:
  32.         SendMessage(hWndActive,WH19_COMMAND,H19_MOVECURSORRIGHT,1L);
  33.         break;
  34.     case VK_LEFT:
  35.         SendMessage(hWndActive,WH19_COMMAND,H19_MOVECURSORLEFT,1L);
  36.         break;
  37.     case VK_HOME:        /* insert character toggle */
  38.         CD.ICToggle = (CD.ICToggle ? FALSE : TRUE);
  39.         break;
  40.     case VK_END:
  41.         SendMessage(hWndActive, WH19_COMMAND, H19_INSERTLINE,1L);
  42.         break;
  43.     case VK_PRIOR:
  44.         SendMessage(hWndActive, WH19_COMMAND,H19_DELETECHAR,1L);
  45.         break;
  46.     case VK_NEXT:
  47.         SendMessage(hWndActive, WH19_COMMAND, H19_DELETELINE,1L);
  48.         break;
  49.     case VK_CLEAR:
  50.         SwitchActiveWindow(TW.hWnd);
  51.         SendMessage(hWndActive, WH19_COMMAND, H19_CURSORHOME,0L);
  52.         break;
  53.     case VK_F6:
  54.         if (GetKeyState(VK_SHIFT) & 0x8000)
  55.         SendMessage(hWndActive, WH19_COMMAND, H19_CLRSCREEN,0L);
  56.         else
  57.         SendMessage(hWndActive, WH19_COMMAND, H19_CLRTOENDOFSCREEN,0L);
  58.         break;
  59.  
  60.     }
  61. }
  62.  
  63. /*
  64.  * Message processing loop.  Return false if no message.
  65.  */
  66. BOOL NEAR DoMessage()
  67. {
  68.  
  69.     MSG msg;
  70.  
  71.   /*
  72.    * Look for a message.  If we have one, remove and process it.
  73.    */
  74.     if (PeekMessage((LPMSG)&msg,NULL,0,0,PM_REMOVE)) {
  75.       /*
  76.        * have to exit.
  77.        */
  78.         if (msg.message == WM_QUIT)
  79.         exit((int)msg.wParam);
  80.        /* 
  81.         * got a key from accelator table.  All shifted, control,
  82.         * and shifted-control function keys are in this table.  
  83.         * We convert them to a WM_COMMAND message and process them there.
  84.         */
  85.     if (TranslateAccelerator(MW.hWnd,hAccel,(LPMSG)&msg) == 0) {
  86.       /* 
  87.            * DoKeyTranslation is our own function.  Here we
  88.            * decide if a key down/up message should be translated to
  89.            * a WM_CHAR message, or if the wParam should be changed
  90.            * to another virtual key code.  If true is returned, the
  91.        * key is translated.
  92.            */
  93.         if (DoKeyTranslation(msg.message, &msg.wParam))
  94.                 TranslateMessage((LPMSG)&msg);
  95.        /*
  96.          * Tell Windows to call our message procedure.
  97.         */
  98.             DispatchMessage((LPMSG)&msg);
  99.     }
  100.     return TRUE;
  101.     }
  102.     return FALSE;
  103. }
  104.  
  105. /* 
  106.  * Return TRUE if key is to be translated.
  107.  */
  108. static BOOL NEAR DoKeyTranslation(unsigned message, WORD *wparam)
  109. {
  110.  
  111.     unsigned shiftstate, numstate;
  112.     int retval = TRUE;
  113.  
  114.   /*
  115.    * if we translate VK_CANCEL, it will become a CTRL-C.  Since
  116.    * we want to use this key for other purposes, we prevent
  117.    * its translation by returning false.
  118.    */
  119.     if ((message == WM_KEYDOWN) || (message == WM_KEYUP)) {
  120.     if (*wparam == VK_CANCEL)
  121.          return FALSE;
  122.  
  123.    /*
  124.     * Similarly, if the virtual key corresponding to the backspace
  125.     * is pressed along with the control key, then we inhibit translation.
  126.     */
  127.     if (*wparam == VK_BACK) {
  128.         if (GetKeyState(VK_CONTROL) & 0x8000)
  129.         return FALSE;
  130.         return TRUE;
  131.     }
  132.  
  133.     /*
  134.      * In the following code, we examine and determine if a key's
  135.      * virtual key code should be changed and/or translated.
  136.      * The situation depends on the state of the H-19 shifted
  137.      * and alternate keypad status as well as the state of
  138.      * the PC's numlock and shift keys.  The correct responses
  139.      * were obtained only by endless experimentation.
  140.      *
  141.      * The main problem is that VK_NUMPAD keys, if translated,
  142.      * become WM_CHAR keys with the numeric valuse 0 to 9 and
  143.      * the decimal point.  This must be prevented, especially
  144.      * when alternate key sequences, i. e. ESC ? v for example,
  145.      * must be sent by the keypad.
  146.      */
  147.         numstate = GetKeyState(VK_NUMLOCK);
  148.         shiftstate = (GetKeyState(VK_SHIFT) & 0x8000) >> 15;
  149.  
  150.     if (CD.ShiftedKeypad) {
  151.         if (numstate | shiftstate) {
  152.             if (InNumpadSet(*wparam))
  153.             *wparam = NumpadToEdit(*wparam);
  154.         else
  155.             *wparam = EditToNumpadLong(*wparam);
  156.         }        
  157.         else
  158.             *wparam = EditToNumpadShort(*wparam);
  159.     }
  160.     else {
  161.         if (!(numstate | shiftstate))
  162.             *wparam = EditToNumpadLong(*wparam);
  163.         else
  164.             *wparam = EditToNumpadShort(*wparam);
  165.     }
  166.     if (CD.AltKeypad)
  167.         if (InNumpadSet(*wparam))
  168.             retval = FALSE;
  169.     }
  170.     return retval;
  171. }
  172.  
  173. /* 
  174.  * Find out if a virtual key is from the numpad set.
  175.  */
  176. static BOOL NEAR InNumpadSet(unsigned val)
  177. {
  178.  
  179.     return(((val >= VK_NUMPAD0) && (val <= VK_NUMPAD9)) || (val == VK_DECIMAL));
  180.  
  181. }
  182.  
  183. /*
  184.  * Change a numpad virtual key code to the corresponding numeric
  185.  * pad code.  Note that numpad keys, if allowed to be translated,
  186.  * become the digits 0 to 9 and the decimal key.
  187.  */
  188. static WORD NEAR NumpadToEdit(unsigned val)
  189. {
  190.  
  191.     switch (val) {
  192.     case VK_NUMPAD1:
  193.         val = VK_END;
  194.         break;
  195.     case VK_NUMPAD2:
  196.         val = VK_DOWN;
  197.         break;
  198.     case VK_NUMPAD3:
  199.         val = VK_NEXT;
  200.         break;
  201.     case VK_NUMPAD4:
  202.         val = VK_LEFT;
  203.         break;
  204.     case VK_NUMPAD5:
  205.         val = VK_CLEAR;
  206.         break;
  207.     case VK_NUMPAD6:
  208.         val = VK_RIGHT;
  209.         break;
  210.     case VK_NUMPAD7:
  211.         val = VK_HOME;
  212.         break;
  213.     case VK_NUMPAD8:
  214.         val = VK_UP;
  215.         break;
  216.     case VK_NUMPAD9:
  217.         val = VK_PRIOR;
  218.         break;
  219.     }
  220.     return val;
  221. }
  222.  
  223. /* 
  224.  * Take care of the insert/delete keys in a short table.
  225.  * Sometimes it is not necessary to check the whole list because
  226.  * we only have to correct the workings of the 0 and decimal keys.
  227.  */
  228. static WORD NEAR EditToNumpadShort(unsigned val)
  229. {
  230.     switch (val) {
  231.     case VK_DELETE:
  232.         val = VK_DECIMAL;
  233.         break;
  234.     case VK_INSERT:
  235.         val = VK_NUMPAD0;
  236.         break;
  237.     }
  238.     return val;
  239. }
  240.  
  241. /*
  242.  * This is called if all the keys must be scanned.
  243.  */
  244. static WORD NEAR EditToNumpadLong(unsigned val)
  245. {
  246.  
  247.     switch (val) {
  248.     case VK_DELETE:
  249.         val = VK_DECIMAL;
  250.         break;
  251.     case VK_INSERT:
  252.         val = VK_NUMPAD0;
  253.         break;
  254.     case VK_END:
  255.         val = VK_NUMPAD1;
  256.         break;
  257.     case VK_DOWN:
  258.         val = VK_NUMPAD2;
  259.         break;
  260.     case VK_NEXT:
  261.         val = VK_NUMPAD3;
  262.         break;
  263.     case VK_LEFT:
  264.         val = VK_NUMPAD4;
  265.         break;
  266.     case VK_CLEAR:
  267.         val = VK_NUMPAD5;
  268.         break;
  269.     case VK_RIGHT:
  270.         val = VK_NUMPAD6;
  271.         break;
  272.     case VK_HOME:
  273.         val = VK_NUMPAD7;
  274.         break;
  275.     case VK_UP:
  276.         val = VK_NUMPAD8;
  277.         break;
  278.     case VK_PRIOR:
  279.         val = VK_NUMPAD9;
  280.         break;
  281.     }
  282.     return val;
  283. }
  284.  
  285. /* 
  286.  * Process string from comm port.  The string is scanned
  287.  * for an ESCAPE character.  If seen, the scanned string is
  288.  * dispatched to the terminal window for display.  Then,
  289.  * the escape sequence is handled.  Frequently, the sequence
  290.  * is broken between strings.
  291.  */
  292. int NEAR H19StringInput(BYTE *str, short len)
  293. {
  294.  
  295.     register BYTE *ptr;
  296.     register short ctr;
  297.     short state;
  298.     BYTE ch;
  299.     int numrem;
  300.  
  301.     while (len) {
  302.     if (state = CD.CommandState) {
  303.         ch = *str & 0x7f;
  304.         if (CD.ANSIMode)
  305.         DoANSICommand(state, ch);
  306.         else
  307.         DoHeathCommand(state, ch);
  308.         str++;
  309.         len -= 1;
  310.     }
  311.     else {
  312.         ctr = 0;
  313.         ptr = str;
  314.         while (len) {
  315.             if ((*ptr &= 0x7f) != ESC) {
  316.             ctr += 1;
  317.             ptr++;
  318.             len -= 1;
  319.         }
  320.         else {
  321.             ptr++;
  322.             len -= 1;
  323.             CD.CommandState = ESC_COMMAND;
  324.             break;
  325.         }
  326.         }
  327.         if (ctr) {
  328.             numrem = (int)SendMessage(hWndActive,WH19_STRINGINPUT,(WORD)ctr,
  329.                     (LONG)(LPSTR)str);
  330.             if (numrem)
  331.             return(len + numrem);        
  332.         }
  333.         str = ptr;
  334.     }
  335.     }
  336.     return (len);
  337. }
  338.  
  339. /* 
  340.  * This routine handles the menu and accelerator keys
  341.  */
  342. void NEAR WndCommand(hWnd, wparam, lparam)
  343. HWND hWnd;
  344. WORD wparam;
  345. LONG lparam;
  346. {
  347.  
  348.     HMENU hMenu;
  349.     HCURSOR hCurOld;
  350.     FARPROC fp;
  351.     int result;
  352.     
  353.     hMenu = GetMenu(hWnd);
  354.  
  355.     switch (wparam) {
  356.     case IDM_RESET:
  357.             ResetTerminal();
  358.         break;
  359.       /*
  360.        * When going from off-line to on-line, the window proc for
  361.        * the main window is changed to the subclass window procedure.
  362.        * In addition, the caret has to be taken down and regenerated
  363.        * and the menu redrawn.
  364.        */
  365.         case IDM_OFFLINE:
  366.             SetWindowLong(MW.hWnd, GWL_WNDPROC, (LONG)MainWndSubclassProc);
  367.         hCurOld = SetCursor(LoadCursor((HANDLE)NULL,IDC_WAIT));
  368.         SendMessage(hWndActive, WH19_CARETFUNCTION, H19_HIDECARET, 0L);
  369.         ChangeMenu(hMenu,IDM_OFFLINE,(LPSTR)szOnline,IDM_ONLINE,
  370.                 MF_BYCOMMAND | MF_CHANGE);
  371.         DrawMenuBar(hWnd);
  372.         CD.LineState = IDM_ONLINE;
  373.         SendMessage(hWndActive, WH19_CARETFUNCTION, H19_SHOWCARET, 0L);
  374.         SetCursor(hCurOld);
  375.         break;
  376.        /*
  377.     * A similar process happens here when going from on-line to off-line
  378.         */
  379.     case IDM_ONLINE:
  380.         SetWindowLong(MW.hWnd, GWL_WNDPROC, (LONG)fpTerminal);
  381.         hCurOld = SetCursor(LoadCursor((HANDLE)NULL,IDC_WAIT));
  382.         SendMessage(hWndActive, WH19_CARETFUNCTION, H19_HIDECARET, 0L);
  383.         ChangeMenu(hMenu,IDM_ONLINE,(LPSTR)szOffline,IDM_OFFLINE,
  384.                     MF_BYCOMMAND | MF_CHANGE);
  385.         DrawMenuBar(hWnd);
  386.         CD.LineState = IDM_OFFLINE;
  387.         SendMessage(hWndActive, WH19_CARETFUNCTION, H19_SHOWCARET, 0L);
  388.         SetCursor(hCurOld);
  389.         break;
  390.        /*
  391.     * The next three commands bring up dialog boxes to change settings.
  392.         */
  393.     case IDM_COMM:
  394.         fp = MakeProcInstance((FARPROC)SetCommParams, hInst);
  395.         result = DialogBox(hInst, MAKEINTRESOURCE(DT_COMM),hWnd,fp);
  396.         break;
  397.     case IDM_TERM:
  398.         fp = MakeProcInstance((FARPROC)SetTermParams, hInst);
  399.         result = DialogBox(hInst, MAKEINTRESOURCE(DT_TERM),hWnd,fp);
  400.         break;
  401.     case IDM_SPECIALKEYS:
  402.         fp = MakeProcInstance((FARPROC)SetStringParams, hInst);
  403.         result = DialogBox(hInst, MAKEINTRESOURCE(DT_STRING),hWnd,fp);
  404.         break;
  405.         /*
  406.      * Most of the action here takes place in the routine
  407.          * which handles the child terminal window.  Here we just
  408.          * sent it a message to do it.  Of course, we had to
  409.          * write the code on the other side to handle it, as well!
  410.          */
  411.     case IDM_COPY:
  412.         SendMessage(TW.hWnd, WH19_SLAPSCREEN, 0, 0L);
  413.         break;                
  414.         /*
  415.      * This piece of code opens the clipboard and copies it to
  416.      * to a buffer.  Later, each line of the buffer is read
  417.          * by the communications processor and sent out the comm port.
  418.      */
  419.     case IDM_PASTE:
  420.         if (OpenClipboard(hWnd)) {
  421.             LPSTR lpClip, lpDest;
  422.         BYTE ch;
  423.  
  424.         hClipData = GetClipboardData(CF_TEXT);
  425.         GB.lBufSize = GlobalSize(hClipData);
  426.         if (GB.hBuf == NULL) {
  427.                 GB.hBuf = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT,
  428.                                 GB.lBufSize);
  429.             if (GB.hBuf != NULL) {
  430.                 GB.lBufHead = GB.lBufTail = 0;
  431.                 lpClip = GlobalLock(hClipData);
  432.                 lpDest = GlobalLock(GB.hBuf);                
  433.                 while(ch = *lpClip++) {
  434.                 if (ch != LF) {
  435.                     *lpDest++ = ch;
  436.                     GB.lBufTail += 1;
  437.                 }
  438.             }
  439.             GlobalUnlock(hClipData);
  440.             GlobalUnlock(GB.hBuf);
  441.                 }
  442.         }
  443.          CloseClipboard();
  444.         }
  445.         break;
  446.     }
  447. }
  448.  
  449. /*
  450.  * This complicated routine reads the comm port when on-line provided
  451.  * the buffer is empty.  Otherwise, it looks to see if anything
  452.  * is left over from a previous attempt at processing.  Normally,
  453.  * the buffer is completely emptied when it is sent to the main
  454.  * window procedure.  However, if hold-screen is in effect, then
  455.  * the terminal window will stop display whenever a carriage return
  456.  * is seen.  In this case, the remaining buffer remains unprocessed
  457.  * until the scroll-lock key is toggled and another line (or screen)
  458.  * can be displayed.
  459.  */
  460. void NEAR ProcessComm()
  461. {
  462.  
  463.     COMSTAT ComStatus;
  464.     int num;
  465.     int retresult = 0;
  466.     int result = 0;
  467.     
  468.     static char Buffer[COMMQUESIZE];
  469.     static int bufsize = 0;
  470.  
  471.   /* if on line, continue */
  472.     if ((CD.LineState == IDM_ONLINE) && !CD.ScrollLock) {
  473.       /* if the buffer is empty, read the comm port */
  474.     if (bufsize == 0) {
  475.             GetCommError(cid, (COMSTAT FAR *)&ComStatus);
  476.       /* if we find something in the comm buffer, get it */
  477.             if (num = ComStatus.cbInQue) {
  478.         num = min(num, BUFSIZE);
  479.           /* if error, ignore it and pass the string along anyway */
  480.             if ((result = ReadComm(cid, (LPSTR)Buffer, num)) < 0) {
  481.             result = -result;
  482.             Buffer[result] = NUL;
  483.         }
  484.         }
  485.     }
  486.     else
  487.         result = bufsize;
  488.  
  489.       /* 
  490.        * We got something on the last read, or the buffer was not empty
  491.        * because the previous dispatch did not read all of it.
  492.        */
  493.     if (result) {
  494.         retresult = H19StringInput(Buffer, result);
  495.       /* if still not empty, move remaining to front of buffer */
  496.         if (retresult) {
  497.         bufsize = retresult;
  498.         memmove(Buffer, Buffer+result-retresult,retresult);
  499.         Buffer[bufsize] = 0;
  500.         }
  501.         else
  502.         bufsize = 0;
  503.     }
  504.      /* 
  505.       * If nothing immediate to process, then check out global buffer
  506.       *    in case something from the clipboard is there.
  507.       */
  508.     else if (GB.hBuf) {
  509.         BYTE FAR *tbuf;
  510.         LONG BufBytesRemaining;
  511.         int count;
  512.  
  513.        /* if not empty, then get another line from buffer */
  514.         BufBytesRemaining = GB.lBufTail - GB.lBufHead;
  515.         if (BufBytesRemaining > 0) {
  516.             tbuf = GlobalLock(GB.hBuf) + GB.lBufHead;
  517.         if (BufBytesRemaining > INT_MAX)
  518.             count = TW.MaxCols;
  519.         else
  520.             count = min(TW.MaxCols, (int)LOWORD(BufBytesRemaining));
  521.          /* send it to the port */
  522.         WriteToPort(cid, tbuf, count);
  523.         GB.lBufHead += count;
  524.         BufBytesRemaining = GB.lBufTail - GB.lBufHead;
  525.             GlobalUnlock(GB.hBuf);
  526.         }
  527.         if (BufBytesRemaining <= 0) 
  528.             GB.hBuf = GlobalFree(GB.hBuf);
  529.     }        
  530.     }
  531. }
  532.